/*
 * The contents of this file are subject to the terms of the Common Development
 * and Distribution License (the License). You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
 * or http://www.netbeans.org/cddl.txt.
 *
 * When distributing Covered Code, include this CDDL Header Notice in each file
 * and include the License file at http://www.netbeans.org/cddl.txt.
 * If applicable, add the following below the CDDL Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.eddm.test.freeconnect;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.eddm.widget.SVGWidget;
import org.netbeans.api.visual.action.ActionFactory;
import org.netbeans.api.visual.action.MoveProvider;
import org.netbeans.api.visual.action.SelectProvider;
import org.netbeans.api.visual.action.WidgetAction;
import org.netbeans.api.visual.anchor.AnchorFactory;
import org.netbeans.api.visual.anchor.AnchorShape;
import org.netbeans.api.visual.anchor.PointShape;
import org.netbeans.api.visual.border.Border;
import org.netbeans.api.visual.border.BorderFactory;
import org.netbeans.api.visual.graph.GraphScene;
import org.netbeans.api.visual.model.ObjectSceneEvent;
import org.netbeans.api.visual.model.ObjectSceneEventType;
import org.netbeans.api.visual.model.ObjectSceneListener;
import org.netbeans.api.visual.model.ObjectState;
import org.netbeans.api.visual.router.Router;
import org.netbeans.api.visual.router.RouterFactory;
import org.netbeans.api.visual.widget.ConnectionWidget;
import org.netbeans.api.visual.widget.LayerWidget;
import org.netbeans.api.visual.widget.Widget;
import org.openide.util.Utilities;




/**
 * @author Alex
 */
public class DemoGraphScene extends GraphScene.StringGraph implements ObjectSceneListener{
    
    private static final URL IMAGE = DemoGraphScene.class.getResource("/svgs/barChart.svg"); // NOI18N
    
    private LayerWidget mainLayer = new LayerWidget(this);;
    private LayerWidget connectionLayer = new LayerWidget(this);
    private LayerWidget interractionLayer = new LayerWidget(this);
    private LayerWidget backgroundLayer = new LayerWidget(this);    
    private Router router = RouterFactory.createFreeRouter();
    
    private WidgetAction moveAction = ActionFactory.createMoveAction ();
    private WidgetAction connectAction = ActionFactory.createExtendedConnectAction(interractionLayer, new SceneConnectProvider(this));
    private WidgetAction resizeAction = ActionFactory.createAlignWithResizeAction (mainLayer, interractionLayer, null, false);
    private WidgetAction reconnectAction = ActionFactory.createReconnectAction(new SceneReconnectProvider(this));
    private WidgetAction moveControlPointAction = ActionFactory.createFreeMoveControlPointAction();
    private WidgetAction selectAction = ActionFactory.createSelectAction(new ObjectSelectProvider());
    private WidgetAction rectangularSelectAction = ActionFactory.createRectangularSelectAction(this, backgroundLayer);
    //private WidgetAction moveAction = ActionFactory.createMoveAction (null, new MultiMoveProvider ());
    
    private NodeMenu nodeMenu=new NodeMenu(this);
    private EdgeMenu edgeMenu=new EdgeMenu(this);
    
    private HashMap<String, SVGWidget> sceneObjects;
    
    private String lastAddedURI;
    
    public DemoGraphScene() {
        addChild(backgroundLayer);
        addChild(connectionLayer);
        addChild(interractionLayer);
        addChild(mainLayer);        
        getActions().addAction(rectangularSelectAction);
        getActions().addAction(selectAction);
        //getActions().addAction(ActionFactory.createPopupMenuAction(new SceneMainMenu(this)));
        setToolTipText("Drop your svg here.");
        initGrids();
        addObjectSceneListener (this, ObjectSceneEventType.values ());        
    }
    
    protected Widget attachNodeWidget(String nodeID) {
    	SVGWidget svgWidget = null;
		
		try {
			svgWidget = new SVGWidget(this, this.lastAddedURI, nodeID);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
//		Border resizeBorder = BorderFactory.createResizeBorder (8, Color.BLACK, true);
//		svgWidget.setBorder(resizeBorder);
		
//		svgWidget.getActions().addAction(resizeAction);
//		svgWidget.getActions().addAction(connectAction);
//    	svgWidget.getActions().addAction(moveAction);
    	//svgWidget.getActions().addAction(selectAction);
    	svgWidget.getActions().addAction(ActionFactory.createPopupMenuAction(nodeMenu));    	
    	
    	mainLayer.addChild(svgWidget);    	
    	
        return svgWidget;
    }
    
    public Widget attachNodeWidget(String node, String uri) throws IOException {
    	this.lastAddedURI = uri;
    	SVGWidget widget = (SVGWidget) addNode(node);  
    	validate();    	
        return widget;
    }
    
    protected Widget attachEdgeWidget(String edge) {
        ConnectionWidget connection = new ConnectionWidget(this);
        connection.setRouter(router);
        connection.setToolTipText("Double-click for Add/Remove Control Point");
        connection.setTargetAnchorShape(AnchorShape.TRIANGLE_FILLED);
        connection.setControlPointShape(PointShape.SQUARE_FILLED_BIG);
        connection.setEndPointShape(PointShape.SQUARE_FILLED_BIG);
        connectionLayer.addChild(connection);
        connection.getActions().addAction(reconnectAction);
        connection.getActions().addAction(createSelectAction());
        connection.getActions().addAction(ActionFactory.createAddRemoveControlPointAction());
        connection.getActions().addAction(moveControlPointAction);
        connection.getActions().addAction(ActionFactory.createPopupMenuAction(edgeMenu));
        return connection;
    }
    
    protected void attachEdgeSourceAnchor(String edge, String oldSourceNode, String sourceNode) {
        ConnectionWidget widget = (ConnectionWidget) findWidget(edge);
        Widget sourceNodeWidget = findWidget (sourceNode);
        widget.setSourceAnchor(sourceNodeWidget != null ? AnchorFactory.createFreeRectangularAnchor(sourceNodeWidget, true) : null);
    }
    
    protected void attachEdgeTargetAnchor(String edge, String oldTargetNode, String targetNode) {
        ConnectionWidget widget = (ConnectionWidget) findWidget(edge);
        Widget targetNodeWidget = findWidget (targetNode);
        widget.setTargetAnchor(targetNodeWidget != null ? AnchorFactory.createFreeRectangularAnchor(targetNodeWidget, true) : null);
    }
    
    private class ObjectSelectProvider implements SelectProvider {
        
        public boolean isAimingAllowed(Widget widget, Point localLocation, boolean invertSelection) {
            return false;
        }
        
        public boolean isSelectionAllowed(Widget widget, Point localLocation, boolean invertSelection) {
            return true;
        }
        
        public void select(Widget widget, Point localLocation, boolean invertSelection) {
            Object object = findObject(widget);
            
            if (object != null) {
                if (getSelectedObjects().contains(object))return;
                userSelectionSuggested(Collections.singleton(object), invertSelection);
            } else
                userSelectionSuggested(Collections.emptySet(), invertSelection);
        }
    }
    
    public void initGrids(){
        Image sourceImage = Utilities.loadImage("test/resources/paper_grid17.png"); // NOI18N
        int width = sourceImage.getWidth(null);
        int height = sourceImage.getHeight(null);
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = image.createGraphics();
        graphics.drawImage(sourceImage, 0, 0, null);
        graphics.dispose();
        TexturePaint PAINT_BACKGROUND = new TexturePaint(image, new Rectangle(0, 0, width, height));
        setBackground(PAINT_BACKGROUND);
        repaint();
        revalidate(false);
        validate();
    }
    
    private class MultiMoveProvider implements MoveProvider {

        private HashMap<Widget, Point> originals = new HashMap<Widget, Point> ();
        private Point original;

        public void movementStarted (Widget widget) {
            Object object = findObject (widget);
            if (isNode (object)) {
                for (Object o : getSelectedObjects ())
                    if (isNode (o)) {
                        Widget w = findWidget (o);
                        if (w != null)
                            originals.put (w, w.getPreferredLocation ());
                    }
            } else {
                originals.put (widget, widget.getPreferredLocation ());
            }
        }

        public void movementFinished (Widget widget) {
            originals.clear ();
            original = null;
        }

        public Point getOriginalLocation (Widget widget) {
            original = widget.getPreferredLocation ();
            return original;
        }

        public void setNewLocation (Widget widget, Point location) {
            int dx = location.x - original.x;
            int dy = location.y - original.y;
            for (Map.Entry<Widget, Point> entry : originals.entrySet ()) {
                Point point = entry.getValue ();
                entry.getKey ().setPreferredLocation (new Point (point.x + dx, point.y + dy));
            }
        }

    }

	@Override
	public void focusChanged(ObjectSceneEvent arg0, Object arg1, Object arg2) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void highlightingChanged(ObjectSceneEvent arg0, Set<Object> arg1,
			Set<Object> arg2) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void hoverChanged(ObjectSceneEvent arg0, Object arg1, Object arg2) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void objectAdded(ObjectSceneEvent arg0, Object arg1) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void objectRemoved(ObjectSceneEvent arg0, Object arg1) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void objectStateChanged(ObjectSceneEvent arg0, Object arg1,
			ObjectState arg2, ObjectState arg3) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void selectionChanged(ObjectSceneEvent arg0, Set<Object> previousSelection,
			Set<Object> newSelection) {
		for(Object o : newSelection) {
			Widget widget = findWidget(o);
			if(widget instanceof SVGWidget )
			{
				SVGWidget svgWidget = (SVGWidget) widget;
				Border resizeBorder = BorderFactory.createResizeBorder (8, Color.BLACK, true);
				svgWidget.setBorder(resizeBorder);
				svgWidget.getActions().addAction(resizeAction);
				svgWidget.getActions().addAction(connectAction);
		    	svgWidget.getActions().addAction(moveAction);
			}
		}
		
		if(newSelection.isEmpty())
		{
			for(Object o : getObjects())
			{
				Widget widget = findWidget(o);
				if(widget instanceof SVGWidget )
				{
					SVGWidget svgWidget = (SVGWidget) widget;			
					svgWidget.setBorder(BorderFactory.createEmptyBorder());
					svgWidget.getActions().removeAction(resizeAction);
					svgWidget.getActions().removeAction(connectAction);
			    	svgWidget.getActions().removeAction(moveAction);
				}
			}
		}
		
	}

	public void deleSelectedNodes(Object[] objects) {
		for(Object o : objects)
		{
			Widget widget = findWidget(o);
			if(widget instanceof ConnectionWidget)
				removeEdge((String)findObject(widget));
			else
				removeNodeWithEdges((String)findObject(widget));
		}
		validate();
	}
}
